package classification.classifier;

import static preprocess.XMLContracter.ATTRIBUTE;
import static preprocess.XMLContracter.NESTING;
import static preprocess.XMLContracter.REPETITION;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;

import preprocess.XMLContracter;
import preprocess.XMLDoc;

import retrieval.StreamWrapper;
import similarity.Similarity;

import classification.calcSimilarity.CalcSimilarityBySLVM;
import classification.slvm.StructSimilarity;

public class StreamClassifier extends ClassifierBySLVM
{
    private StreamWrapper    sw             = null;
    private Similarity       calcSimilarity = null;
    private File[]           trainingFiles  = null;
    private SAXReader        reader         = null;
    private XMLContracter con = null;

    private StructSimilarity optSimiMatrix  = null;

    private int              traFileNum     = 0;
    private String[]         categoryIDs   = null;

    public StreamClassifier(StreamClassifierInfo info)
    {
        getReady(info);
    }

    private void getReady(StreamClassifierInfo info)
    {
        /* 创建分类需要的对象 */
        this.sw = new StreamWrapper();
        this.reader = new SAXReader();
        this.con = new XMLContracter();

        /* 从 StreamClassifierInfo中加载分类信息 */
        this.calcSimilarity = info.getSimilarity();
        this.KNN = info.getKNNNum();
        this.category_num = info.getClassNum();
   
        /* 找到训练文件 */
        String traFilePath = this.XMLs_PATH + "same_size_" + this.category_num;
        File traDir = new File(traFilePath);
        this.trainingFiles = this.getFileList(traDir);
        
        /* 找到待分类的类别名 */
        this.categoryIDs = new String[this.category_num];
        int index = 0;
        for(File file : traDir.listFiles())
        {
            this.categoryIDs[index++] = file.getName();
        }

        ArrayList<File> fileArr = new ArrayList<File>();
        for (File file : this.trainingFiles)
        {
            fileArr.add(file);
        }

        /* 找到训练文件的文件数目信息 */
        this.traFileNum = fileArr.size();

        /* 找到训练文件的文件ID信息 */
        this.docIDSet = this.exploreDocID(fileArr);

        /*
         * 找到所有XML文件的类别信息
         */
        if ((this.categoryMap = this.exploreCategory()) == null)
        {
            stdErr.println("Error occur in category explore process");
        }

        /* 设置当前最有结构相似度矩阵 */
        if (this.calcSimilarity instanceof CalcSimilarityBySLVM)
        {
            /* 得到当前最优结构相似度矩阵 */
            this.optSimiMatrix = this.loadStructSimilarity();
            ((CalcSimilarityBySLVM) this.calcSimilarity)
                    .setStructSimilarity(optSimiMatrix);
        }
    }

    public ClassifyResult classify(byte[] streams, String fileName)
    {
        try
        {
            /* 得到测试文件的XMLDoc对象 */
            Document doc = sw.stream2doc(streams);
            doc = con.contract(doc, NESTING | REPETITION | ATTRIBUTE);
            XMLDoc TestXMLDoc = new XMLDoc(doc,fileName);

            /* 计算该测试文件与所有训练文件的相似度 */
            double[] simiResult = new double[this.traFileNum];
            for (int traIndex = 0; traIndex < this.traFileNum; traIndex++)
            {
                File traFile = this.trainingFiles[traIndex];
                String traFileName = traFile.getName();
                int traPartition = traFileName.lastIndexOf(".");
                String traDocID = traFileName.substring(0, traPartition);

                Document traDoc = this.reader.read(traFile);
                traDoc = con.contract(traDoc, NESTING | REPETITION | ATTRIBUTE);
                XMLDoc traXMLDoc = new XMLDoc(traDoc,traDocID);
                
                simiResult[traIndex] = this.calcSimilarity.calcSimilarity(
                        TestXMLDoc, traXMLDoc);
            }

            /* 找到KNN分类结果 */
            ClassifyResult result = this.KNNValueClassify(simiResult,
                    this.docIDSet);

            return result;
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            return null;
        }
    }

    @Override
    protected double test(ArrayList<File> fileArr, ArrayList<File> traFileArr)
    {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    protected boolean training(ArrayList<File> fileArr)
    {
        // TODO Auto-generated method stub
        return false;
    }
    
    public String[] getCategoryIDs()
    {
        return this.categoryIDs;
    }

    public static void main(String[] args) throws IOException
    {
        StreamClassifierInfo info = new StreamClassifierInfo(4, 400,
                new CalcSimilarityBySLVM());
        StreamClassifier classifier = new StreamClassifier(info);

        File[] files = new File(
                "G:/XML_Stream_Process/classification/src/same_size_2/2112299")
                .listFiles();
        for (File file : files)
        {
            BufferedReader reader = new BufferedReader(new FileReader(file));
            StringBuffer buffer = new StringBuffer();
            String line = "";
            while ((line = reader.readLine()) != null)
            {
                buffer.append(line);
            }

            byte[] streams = buffer.toString().getBytes();

            System.out.println(file.getName()
                    + ":"
                    + classifier.classify(streams, file.getName())
                            .getCategory());
        }
    }
}
